import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:ffi/ffi.dart';

import 'dart:io';

import 'package:flutter/services.dart';
import 'package:skynet_crypt/skynet_crypt.dart' as skynet_crypt;

void main() {
  runApp(const MyApp());
}

// String GetHmac64(String x, String y) {
//   Pointer<Utf8> p1 = x.toNativeUtf8();
//   Pointer<Utf8> p2 = y.toNativeUtf8();

//   var s = skynet_crypt.hmac64(p1, p2);

//   calloc.free(p1);
//   calloc.free(p2);
//   return s;
// }

// String GetSecret(String x, String y) {
//   Pointer<Utf8> p1 = x.toNativeUtf8();
//   Pointer<Utf8> p2 = y.toNativeUtf8();

//   var s = skynet_crypt.desencode(p1, p1.length, p2, p2.length);

//   calloc.free(p1);
//   calloc.free(p2);
//   return s;
// }

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  SocketClient? sock;
  String _status = '未链接';
  String _txt = "";
  int step = 0;

  String challenge = "";
  String clientkey = "";
  String serverkey = "";
  String secretkey = "";
  String secret = "";
  String hmac = "";

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  _onConnect(SocketClient client) {
    step = 0;
    setState(() {
      _status = "已连接";
    });
    debugPrint(" 连接服务器成功 ${client.host}:${client.port} ");
  }

  _onData(SocketClient client, String s) async {
    debugPrint("============>$s");

    switch (step) {
      case 0:
        challenge = s;
        debugPrint("challenge=$challenge");
        clientkey = skynet_crypt.randomkey();
        debugPrint("clientkey=$clientkey");
        var exchClientKey = skynet_crypt.dhexchange(clientkey);
        debugPrint("exchClientKey=$exchClientKey");
        sock!.send(exchClientKey);
        step = 1;
        break;
      case 1:
        serverkey = s;
        if (true) {
          debugPrint("serverkey=$serverkey");
          secret = skynet_crypt.dhsecret(serverkey, clientkey);
          debugPrint("secret=$secret");
        }

        if (true) {
          hmac = skynet_crypt.hmac64(challenge, secret);
          debugPrint("hmac=$hmac");
          sock!.send(hmac);
        }

        if (true) {
          var user = base64Encode("jack".codeUnits);
          var server = base64Encode("12345678".codeUnits);
          var password = base64Encode("password".codeUnits);
          // ignore: unnecessary_string_escapes
          var token = "${user}@${server}:$password";
          debugPrint("token=$token");

          var etoken = skynet_crypt.desencode(secret, token);
          debugPrint("etoken=$etoken");
          step = 2;
          sock!.send(etoken);
        }

        break;
      default:
    }
  }

  _onDone(SocketClient client) {
    setState(() {
      _status = "断开连接";
    });
    debugPrint(" 服务器断开连接 ");
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {}

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: Column(
            children: [
              Center(
                child: Text(_status),
              ),
              Center(
                child: Text(_txt),
              ),
              ElevatedButton(
                child: const Text("连接服务器"),
                onPressed: () {
                  if (sock == null || !sock!.isConn) {
                    sock = SocketClient("192.168.3.25", 8001,
                        onConnect: _onConnect,
                        onData: _onData,
                        onDone: _onDone,
                        reconnectInterval: 1000,
                        reconnectCount: 0,
                        useMsgPack: false);

                    sock!.connect();
                  }
                },
              )
            ],
          )),
    );
  }
}

/// TCP 客户端，支持json和msgpack两种格式.
class SocketClient {
  Socket? _socket;

  /// 服务器IP地址
  final String _host;

  /// 端口
  final int _port;

  /// 重连次数
  int? reconnectCount;

  /// 重连时间间隔
  int? reconnectInterval;

  /// 重连定时器
  bool socketOpened = false;

  /// 是否使用msgpack
  bool? useMsgPack;

  List<int> buff = [];

  /// 服务器IP
  String get host => _host;

  /// 服务器端口
  int get port => _port;

  int _curReconn = 0;

  Timer? _timer;

  int _seq = 0;

  bool _closeBySelf = false;

  bool _isConn = false;

  bool get isConn => _isConn;

  /// 当前重连次数
  int get curReconnect => _curReconn;

  void Function(SocketClient client, String cmd)? onData;

  void Function(SocketClient client)? onConnect;

  void Function(SocketClient client)? onDone;

  SocketClient(
    this._host,
    this._port, {
    required this.onConnect,
    required this.onData,
    this.onDone,
    this.useMsgPack,
    this.reconnectCount,
    this.reconnectInterval,
  }) {
    reconnectCount ??= -1;
    reconnectInterval ??= 3000;
    useMsgPack ??= false;
  }

  /// 连接服务器
  Future<void> connect() async {
    buff = [];
    debugPrint("开始连接...");
    await Socket.connect(host, port).then((Socket socket) {
      _socket = socket;
      _curReconn = 0;
      _closeBySelf = false;
      _isConn = true;

      onConnect!(this);
      socket.listen((data) {
        debugPrint("data=$data");
        _onData(data);
      }, onError: (error, stack) {
        debugPrint(" socket error = $error");
        _isConn = false;
        var tmp = reconnectCount!.toUnsigned(32);
        if (_curReconn < tmp && !_closeBySelf) {
          onDone!(this);
        } else {
          _reConn();
        }
      }, onDone: () async {
        _isConn = false;
        if (!_closeBySelf) {
          var tmp = reconnectCount!.toUnsigned(32);
          if (_curReconn < tmp) {
            _reConn();
          } else {
            onDone!(this);
          }
        } else {
          onDone!(this);
        }
      });
    }).catchError((e) {
      _isConn = false;
      debugPrint(" socket error = $e");
      _reConn();
    });
  }

  /// 断开连接
  close() {
    _closeBySelf = true;
    _isConn = false;
    _socket?.close();
    _curReconn = 0;
    _socket?.destroy();
    // buff = [];
  }

  dispose() {
    _seq = _seq + 1;
    _socket?.close();
    _socket?.destroy();
  }

  void _reConn() async {
    int curSeq = _seq;
    Future.delayed(Duration(milliseconds: reconnectInterval!), () {
      var tmp = reconnectCount!.toUnsigned(32);
      if (curSeq == _seq && _curReconn < tmp && !_closeBySelf) {
        _socket = null;
        _curReconn += 1;
        debugPrint("正在进行断线重连 $_curReconn");
        connect();
      }
    });
  }

  _onData(Uint8List event) async {
    // debugPrint('----------> $event  type=${event.runtimeType}');
    buff += event;
    debugPrint('当前的缓冲区长度为: ${buff.length}');

    while (buff.length >= 2) {
      int index = buff.indexOf(10, 0);
      debugPrint("搜索索引$index");
      if (index > -1) {
        List<int> packed = buff.sublist(0, index);
        var decoded = utf8.decode(packed);
        debugPrint("decode=$decoded");
        buff.replaceRange(0, index + 1, []);
        onData!(this, decoded);
      } else {
        break;
      }
    }
  }

  /// 发送数据
  send(String s) {
    debugPrint("<============$s");
    String ss = s + "\n";
    var bytes = ss.codeUnits;
    _socket!.add(bytes);
  }
}
